{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 打印所有单行变量\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 个人理解:  \n",
    "> python一切皆对象，可以分为静态对象和动态对象。  \n",
    "> 静态对象：数字，字符串(现实中的大小，颜色等)  \n",
    "> 动态对象：函数(现实中各种动作，扔东西会下落，打玻璃会碎等)  \n",
    "\n",
    "既然函数也是对象，所以函数作为其他函数的参数，或者被return  \n",
    ">前面经常用的dir()和help()就是把函数对象作为参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 闭包\n",
    "\n",
    "> 在一些语言中，在函数中可以（嵌套）定义另一个函数时，如果内部的函数引用了外部的函数的变量，则可能产生闭包。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "<function abs>"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abs(-10)  # -->\n",
    "abs       # abs(-10)是函数调用，而abs是函数本身"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'abs'"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "<function abs>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'abs'"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abs.__name__  # -->\n",
    "f = abs       # 对象指向f标签\n",
    "f             # -->\n",
    "f(-10)        # -->\n",
    "f.__name__    # --> 本质还是原来的abs对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.foo.<locals>.bar>"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "94"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def foo(a, b, c):\n",
    "    def bar(x):\n",
    "        return a*x**2 + b*x + c  # 向上层作用域搜索a,b,c\n",
    "    return bar                   # 返回一个函数对象\n",
    "\n",
    "y = foo(2, 3, 4)\n",
    "\n",
    "y            # --> \n",
    "y(6)  # -->"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<cell at 0x7f04bc298be8: int object at 0x559466dd3f60>,\n",
       " <cell at 0x7f04bc298648: int object at 0x559466dd3f80>,\n",
       " <cell at 0x7f04bc298e58: int object at 0x559466dd3fa0>)"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.__closure__                   # --> cell对象的元组\n",
    "y.__closure__[0].cell_contents  # --> 每个cell对象携带着外部参数\n",
    "y.__closure__[1].cell_contents  # -->\n",
    "y.__closure__[2].cell_contents  # -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Decorator(装饰器）\n",
    "\n",
    "> 装饰模式有很多经典的使用场景，例如插入日志、性能测试、事务处理等等，有了装饰器，就可以提取大量函数中与本身功能无关的类似代码，从而达到代码重用的目的\n",
    "\n",
    "装饰器通常用于在不改变原有函数代码和功能的情况下，为其添加额外的功能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'hello'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'bar'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'<i>hello world</i>'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def hello():                # 创建基础函数\n",
    "    return 'hello world'\n",
    "\n",
    "def foo(func):\n",
    "    def bar():\n",
    "        return \"<i>\" + func() + \"</i>\"  # 调用形参\n",
    "    return bar                          # 返回函数对象\n",
    "\n",
    "hello.__name__      # -->\n",
    "hello = foo(hello)  # hello变量指向了foo.<locals>.bar\n",
    "hello.__name__      # -->\n",
    "hello()             # --> 本质是调用了foo.<locals>.bar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### @ 语法糖\n",
    "\n",
    "使用装饰器提供的 @ 语法糖（Syntactic Sugar）简化代码:\n",
    "\n",
    "```\n",
    "@decorator  # <=> func = decorator(func)\n",
    "def func():\n",
    "    pass\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.foo.<locals>.bar>"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'bar'"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'<i>hello world</i>'"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def foo(func):\n",
    "    def bar():\n",
    "        return \"<i>\" + func() + \"</i>\"\n",
    "    return bar\n",
    "\n",
    "@foo          # 语法糖会处理最近的函数等效与hello = foo(hello)\n",
    "def hello():\n",
    "    return 'hello world'\n",
    "\n",
    "hello           # -->\n",
    "hello.__name__  # --> 这里的hello只是一个指向foo.<locals>.bar函数的变量\n",
    "hello()         # -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对带参数的函数进行装饰"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<i>hello python</i>'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'<i>hello python and markdwon</i>'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def foo(func):\n",
    "    def bar(*arg, **kwargs):\n",
    "        ret = func(*arg, **kwargs)\n",
    "        return \"<i>\" + ret + \"</i>\"\n",
    "    return bar\n",
    "\n",
    "@foo\n",
    "def hello(name):\n",
    "    return 'hello {}'.format(name)\n",
    "\n",
    "@foo\n",
    "def say(name1, name2):\n",
    "    return 'hello {0} and {1}'.format(name1,name2)\n",
    "\n",
    "hello('python')            # -->\n",
    "say('python', 'markdwon')  # -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 带参数的装饰器\n",
    "\n",
    "带参数的装饰器\n",
    "```\n",
    "@foo(arg1, arg2)  # <=> func = foo(arg1, arg2)(func)\n",
    "def func():\n",
    "    pass\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<b>hello python</b>'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def bar_tags(tag):\n",
    "    def foo(func):\n",
    "        def bar(*arg, **kwargs):\n",
    "            ret = func(*arg, **kwargs)\n",
    "            return '<' + tag + '>' + ret + '</' + tag + '>'\n",
    "        return bar\n",
    "    return foo\n",
    "\n",
    "@bar_tags('b')  # 根据不同参数返回不同的装饰器\n",
    "def hello(name):\n",
    "    return 'hello {}'.format(name)\n",
    "\n",
    "hello('python')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多个装饰器\n",
    "\n",
    "装饰器可以定义多个，离函数定义最近的装饰器先被调用\n",
    "\n",
    "```\n",
    "@foo      # <=> func = foo(bar(func))\n",
    "@bar\n",
    "def func():\n",
    "    pass\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<i><b>hello world</b></i>'"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def foo(func):\n",
    "    def bar():\n",
    "        return \"<i>\" + func() + \"</i>\"\n",
    "    return bar\n",
    "\n",
    "def add_tag(func):\n",
    "    def bar():\n",
    "        return '<b>' + func() + '</b>'\n",
    "    return bar\n",
    "\n",
    "@foo\n",
    "@add_tag\n",
    "def hello():\n",
    "    return 'hello world'\n",
    "\n",
    "hello()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基于类的装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<b>hello world</b>'"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Bold(object):\n",
    "    def __init__(self, func):\n",
    "        self.func = func\n",
    "\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        return '<b>' + self.func(*args, **kwargs) + '</b>'\n",
    "\n",
    "@Bold\n",
    "def hello(name):\n",
    "    return 'hello %s' % name\n",
    "\n",
    "hello('world')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类 Bold 有两个方法：\n",
    "* `__init__()`：它接收一个函数作为参数，也就是被装饰的函数  \n",
    "* `__call__()`：让类对象可调用，就像函数调用一样，在调用被装饰函数时被调用\n",
    "\n",
    "> 如果类装饰器有参数，则 `__init__ `接收参数，而 `__call__` 接收 func\n",
    "\n",
    "> 使用装饰器有一个瑕疵，就是被装饰的函数，它的函数名称已经不是原来的名称,为了消除这样的副作用，Python 中的 functool 包提供了一个 wraps 的装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<i>hello world</i>'"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Tag(object):\n",
    "    def __init__(self, tag):\n",
    "        self.tag = tag\n",
    "\n",
    "    def __call__(self, func):\n",
    "        def wrapped(*args, **kwargs):\n",
    "            return \"<{tag}>{res}</{tag}>\".format(\n",
    "                res=func(*args, **kwargs), tag=self.tag\n",
    "            )\n",
    "        return wrapped\n",
    "\n",
    "@Tag('i')\n",
    "def hello(name):\n",
    "    return 'hello %s' % name\n",
    "\n",
    "hello('world')"
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4rc1"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": "15",
    "lenType": "10",
    "lenVar": "60"
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
